#include <linux/init.h>
#include <linux/module.h>

#include <linux/pci.h>
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/pm.h>
#include <linux/pm_runtime.h>
#include <linux/init.h>
#include <linux/aer.h>
#include <linux/dmi.h>


#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/export.h>
#include <linux/pci.h>
#include <linux/init.h>
#include <linux/ioport.h>
#include <linux/errno.h>
#include <linux/memblock.h>


/* 
	用来调试PCIE驱动，读写数据使用  
*/
static struct pci_bus * findbus;


static void rdump_pci_info(struct pci_bus * bus)
{
	struct pci_bus *tmpbus;
	struct pci_dev *tmppci;
	if(bus && bus->children.next){
		list_for_each_entry(tmpbus, &bus->children, node) {
			rdump_pci_info(tmpbus);
		}
	}
	printk("pci bus_name is %s:number=%d,primary=%d\n",bus->name, bus->number,bus->primary);
	list_for_each_entry(tmppci, &bus->devices, bus_list) {
		printk("devfn = %x, vendor=%x,device=%x,class=%x,subven=%x,sub_dev=%x\n",
			tmppci->devfn,tmppci->vendor,tmppci->device,tmppci->class,tmppci->subsystem_vendor,tmppci->subsystem_device);
	}
}

static void rfind_pci_bus(struct pci_bus * bus, int bus_num)
{
	struct pci_bus *tmpbus;


	if(bus && bus->children.next){
        if(bus->number == bus_num){
            findbus = bus;
	        printk("OK,find name is %s:number=%d,primary=%d\n",bus->name, bus->number,bus->primary);
            return;
        }
		list_for_each_entry(tmpbus, &bus->children, node) {
			rfind_pci_bus(tmpbus,bus_num);
		}
	}
}

static int __init pcie_test_init(void)
{
	struct pci_bus *bus;
	struct pci_dev *tmppci;
    struct pci_ops *ops;
    struct resource * r;
    unsigned int tmp_val = 0;
    int loop = 0;
	unsigned long mmio_start, mmio_end, mmio_flags, mmio_len; 
	void *ioaddr = NULL; 
	const unsigned char *cioaddr = NULL;

	// list  pci_device & pci_bus
	printk("pcie_test_init:%s\n",__FUNCTION__);
	printk("\ndump pci_info\n");
	list_for_each_entry(bus, &pci_root_buses, node) {
		rdump_pci_info(bus);
	}

	printk("\ndump video info\n");
    // find video bus
	list_for_each_entry(bus, &pci_root_buses, node) {
		rfind_pci_bus(bus,1);
	}
    if (findbus){
        bus = findbus;
    }
	printk("find-name is %s:number=%d,primary=%d\n",bus->name, bus->number,bus->primary);
    tmppci = pci_get_slot(bus, 0); 
    printk("devfn = %x, vendor=%x,device=%x,class=%x,subven=%x,sub_dev=%x\n",
        tmppci->devfn,tmppci->vendor,tmppci->device,tmppci->class,tmppci->subsystem_vendor,tmppci->subsystem_device);
    ops = tmppci->bus->ops;

#if 1 // debug resource
    r = tmppci->resource;
    for(loop=0;loop<DEVICE_COUNT_RESOURCE; ++loop){
        printk("resource: start:%#llx,end:%#llx,name:%s,flags:%#lx,desc:%#lx\n",
                        r->start,r->end,r->name,r->flags,r->desc);
        r++;
    }
#endif    

#if 1  // Read config space
    printk("%.2x: ",loop);
    for(loop=0; loop < 64;++loop){
        if(loop % 16 == 0)
            printk("\n%.2x: ",loop);
        ops->read(bus,0,loop,1,&tmp_val);
        printk("%.2x ",tmp_val&0xff);
    }
    printk("\n%.2x: ",loop);
#endif



	return 0;//成功返回0，失败返回错误码
}

static void __exit pcie_test_exit(void)
{
		printk("pcie_test_exit:%s\n",__FUNCTION__);
		return;
}


module_init(pcie_test_init);
module_exit(pcie_test_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("baiy <baiyang0223@163.com>");
MODULE_DESCRIPTION("This is a test driver");
MODULE_VERSION("1.0.0.0");
